
#include "WebServer.h"
/* 静态变量需要初始化在.cpp中定义 */
#ifdef ESP32
String WebServer::wsData;
String WebServer::wsDataNews;
#endif
// 静态成员初始化，确保它只在这里初始化一次
AsyncWebSocket WebServer::ws("/ws");
WebServer::WebServer()
  : server(8866), interval(100000), previousMillis(0) {  //构造函数初始化后初始化server及websocket;及两个长整数变量
}
/* 判断字符串数据是否与本地数据匹配 */

/* 异步服务构造函数 */  // == == == == == == == == == == == == == == == == == == == == = webSocket == == == == == == == == == == == == == == == == ==
/* WebSocket客户进入处理函数 */
void WebServer::onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
  /* Serial.println(client->id());
  Serial.println((char *)data);
  Serial.println(server->url());
  client->printf("[%s]", (char *)data); */
  switch (type) {
    case WS_EVT_CONNECT:  //客户端建立连接
      Serial.printf("ws[%s][%u] connect\n", server->url(), client->id());
      client->printf("Hello Client %u !", client->id());  // 向客户端发送数据
      client->ping();
      break;
    case WS_EVT_DISCONNECT:  //客户端断开连接
      Serial.printf("ws[%s][%u] disconnect: %u\n", server->url(), client->id());
      break;
    case WS_EVT_PONG:  //收到客户端发送的ping进行应答(pong消息)
      Serial.printf("ws[%s][%u] pong[%u]: %s\n", server->url(), client->id(), len, (len) ? (char *)data : "");
      break;
    case WS_EVT_DATA:
      {  //收到客户端发送数据
        AwsFrameInfo *info = (AwsFrameInfo *)arg;
        //Serial.printf("ws[%s][%u] frame[%u] %s[%llu - %llu]: ", server->url(), client->id(), info->num, (info->message_opcode == WS_TEXT) ? "text" : "binary", info->index, info->index + len);
        data[len] = 0;  //设置结束符\0
        //Serial.printf("%s\n", (char *)data);

        String msg = String((char *)data);  // Correctly convert data to String
        responseDataWS(client, msg);        //响应webSocket数据函数
        break;
        /* 添加处理获取的数据函数 ----------------------------------------------------------------------------------------------*/
      }
    case WS_EVT_ERROR:  //发生错误
      Serial.printf("ws[%s][%u] error(%u): %s\n", server->url(), client->id(), *((uint16_t *)arg), (char *)data);
      break;
  }
}
/* 指定时间清理断开的连接 */
void WebServer::WebSocketCleaner() {
/* 在ESP32中直接使用事件反射会出错 */
#ifdef ESP32
  if (wsData != wsDataNews) {
    ws.textAll(wsDataNews);
    wsData = wsDataNews;
    Serial.printf("变量wsDataNews=%s", wsDataNews.c_str());
  }
#endif
  unsigned long currentMillis = millis();  //获取当前毫秒数
  // 检查是否达到清理间隔
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;  // 更新上一次清理的时间
    Serial.printf("\nclear WebSocket:%d", interval);
    handleClients();  // 执行清理操作
  }
}
/* 清理并断开超过(esp32:32,esp8266:8)个的websocket连接 */
void WebServer::handleClients() {
  ws.cleanupClients();  // 清理已断开的客户端
}

//=================================================================webSocket end=============================================================
/* 初始化函数 */
void WebServer::begin() {
  /* 添加websocket到服务 */
  server.addHandler(&ws);
  /* 添加websocket连接处理函数 */
  ws.onEvent([this](AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
    this->onWsEvent(server, client, type, arg, data, len);
  });
  controller.setEventCallback(onEventReceived);

  /* 首页返回内置的html网页 */
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
    request->send_P(200, "text/html", index_html);
  });

  /* 控制指令通过此处进行 */
  server.on(
    "/post", HTTP_POST, [this](AsyncWebServerRequest *request) {
      String json;
      Serial.println("---");
      /* 获取头文件中指定的数据行 */
      if (request->hasHeader(PARAM_MESSAGE)) {
        json = request->getHeader(PARAM_MESSAGE)->value();
      } else if (request->hasParam(PARAM_MESSAGE, true)) {
        json = request->getParam(PARAM_MESSAGE, true)->value();
      }

      if (json != "") {
        responseData(request, json);
        Serial.printf("\nheaderJSON:%s\n", json);
      }
    },
    /* 获取post响应体内容 */
    NULL, [this](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) {
      String json;

      for (size_t i = 0; i < len; i++) {
        json += (char)data[i];
      }
      responseData(request, json);
    });

  /* 添加跨域 跨域请求会先发送OPTIONS请求允许后再发送POST正式数据 */
  server.on("/post", HTTP_OPTIONS, [](AsyncWebServerRequest *request) {
    AsyncWebServerResponse *response = request->beginResponse(200);
    response->addHeader("Access-Control-Allow-Origin", "*");
    response->addHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
    response->addHeader("Access-Control-Allow-Headers", "Content-Type");
    request->send(response);
  });
  /* 处理异步错误*/
  server.onNotFound([this](AsyncWebServerRequest *request) {
    this->notFound(request);
  });

  server.begin();  // 开启服务器
  Serial.println("WebServer start!");
}


/* 发生错误处理函数 */
void WebServer::notFound(AsyncWebServerRequest *request) {
  request->send(404, "text/plain", "Not found");
}

/* 异步HTTP响应数据函数 */
void WebServer::responseData(AsyncWebServerRequest *request, const String &json) {

  /* 添加处理获取的数据函数 ----------------------------------------------------------------------------------------------*/
  String result = dataContorl(json);  //硬件控制程序返回结果
  /* 添加跨域头将内容添加到响应头中返回 */
  AsyncWebServerResponse *response = request->beginResponse(200, "application/json;charset=utf-8", result);
  response->addHeader("Access-Control-Allow-Origin", "*");  // 允许所有来源
  request->send(response);
}
/* 响应webSocket数据函数 */
void WebServer::responseDataWS(AsyncWebSocketClient *client, const String &json) {
  String result = dataContorl(json);  //硬件控制程序返回结果
  Serial.print("result=");
  Serial.println(result);
  client->text(result);
  // client->text(json + "|" + (client->remoteIP()).toString() + ":" + String(client->remotePort()));
  //Serial.printf("\nlocalStorage.getItem('key'):%s+++++++++++++++++++++++++++++++++++++++++++++++++", localStorage.getItem("key").c_str());
  //access.del("刘菲菲");
  //Serial.printf("\nlocalStorage.getItem('key'):%s++++++++++++++++++++++++++++++++++++++++++++++++++", localStorage.getItem("key").c_str());
  //Serial.printf("localStorage.getItem('key'):%s", localStorage.getItem("key"));
}
String WebServer::dataContorl(const String &json) {
  JSONVar control = JSON.parse(json);
  String userkey = "";

  /* 判断是否存在JSON数据 */
  if (JSON.typeof(control) == "undefined") {
    Serial.println("\ndataContorl:Parsing control undefined!");
    return "{\"error\":\"数据不正确！\"}";
  }
  /* 判断userkey与K是否存在 */
  if (control.hasOwnProperty("userkey") && control.hasOwnProperty("K")) {
    if (access.keyMatching((String)control["userkey"]) == true) {  //匹配本地密钥是否正确,若正确根据功能码实现相应功能
      String controlValue = (String)control["K"];
      //判断K的控制代码控制相应分支
      if (controlValue == "open") {  //打开车库
        Serial.println("打开车库");
        controller.open();
        return "{\"msg\":\"开控制成功！\"}";
      } else if (controlValue == "close") {  //关闭车库
        Serial.println("关闭车库");
        controller.close();
        return "{\"msg\":\"关控制成功！\"}";
      } else if (controlValue == "readStatus") {  //读取门状态
        Serial.println("读取状态");
        String status = controller.readSwitch();
        Serial.println(status);
        return status;
      } else if (controlValue == "reconnect") {  //通过userkey实现userkey重置并返回
        userkey = access.changekey(control["userkey"]);
        return userkey != "" ? "{\"userkey\":\"" + userkey + "\"}" : "{\"error\":\"密钥不存在！\"}";  //-------------------------
      } else if (controlValue == "readMotor") {                                                       //读取电机状态
        Serial.println("读取状态");
        String motorStatus = controller.readMotor();
        Serial.println(motorStatus);
        return motorStatus;
      } else {
        return "{\"error\":\"未找到匹配命令！\"}";
      }
    } else {
      return "{\"error\":\"密钥不正确！\"}";
    }
  } else if (control.hasOwnProperty("username") && control.hasOwnProperty("password") && control.hasOwnProperty("K")) {
    /* 根据K==resetUserkey和用户名密码正确修改userKey值 */
    if (access.userMatching(control["username"], control["password"]) == true && (String)control["K"] == "resetUserkey") {  //通过用户名密码重置+K指令重置userkey密码
      Serial.println("用户名密码正确(重置userkey)！");
      access.add(control["username"], control["password"]);  //添加后会自动去重并变换添加userkey;
      userkey = access.readkey(control["username"], control["password"]);
      Serial.printf("\nuserkey:%s\n", userkey.c_str());
      return userkey == "" ? "{\"error\":\"密钥创建失败！\"}" : "{\"userkey\":\"" + userkey + "\"}";  //----------------------------------
    /* 根据K==manager和管理员用户名密码正确返回 "{\"admin\":\"succeed\"}"失败返回错误提示信息 */
    }else if((String)control["K"] == "manager"){//管理员密码登录设置界面
      String manager=localStorage.getItem("manager");//获取本地管理用户名密码json文本
      if(manager!=""){//若存在则与本地用户名密码做比较成功返回"{\"admin\":\"succeed\"}"
       return manager=="{\"username\":\"" + (String)control["username"] + "\",\"password\":\"" + (String)control["password"] + "\"}"?"{\"admin\":\"succeed\"}":"{\"error\":\"管理员用户或密码错误!\"}";
      }else{//若本地json文本不存在将添加默认管理员用户名密码到本地
        localStorage.setItem("manager","{\"username\":\"admin\",\"password\":\"admin99999\"}");//添加默认管理员用户名密码到本地
        if((String)control["username"]=="admin" && (String)control["password"]=="admin99999"){//判断默认管理员用户名密码是否正确
         return "{\"admin\":\"succeed\"}";
        }else{
         return "{\"error\":\"管理员默认用户或密码错误!\"}";
        }
      }
    //}else if((String)control["K"] == "manager"){//管理员密码登录设置界面
      

    } else {
      return "{\"error\":\"密码错误！\"}";
    }
  } else {
    return "{\"error\":\"JSON格式不正确!\"}";
  }
}

// 类A中的函数，用来处理来自类B的事件,中断函数事件跨类触发
void WebServer::onEventReceived(const String &data) {
#ifdef ESP32
  wsDataNews = data;
#elif defined(ESP8266)
//#else defined(esp8266)
  ws.textAll(data);
#endif
  Serial.print("\nClassA received event with data: ");
  Serial.println(data);  // 打印事件数据
}